/**
 * WISHLIST
 * - need to allow users to remove real mappings.
 * - add functionality to convert temporary decision to approved decision
 * - filter for temporary versus non-temporary mappings in visualization and Prompt
 */

package ca.uvic.cs.cogz.mapping;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableColumn;

import ca.uvic.cs.cogz.mapping.ontology.DataLoaderFacade;
import ca.uvic.cs.cogz.util.IconConstants;
import edu.stanford.smi.protegex.prompt.actionLists.ActionArgs;
import edu.stanford.smi.protegex.prompt.event.PromptEvent;
import edu.stanford.smi.protegex.prompt.event.PromptListener;
import edu.stanford.smi.protegex.prompt.event.PromptListenerManager;
import edu.stanford.smi.protegex.prompt.operation.MergeClsesOperation;
import edu.stanford.smi.protegex.prompt.operation.Operation;
import edu.stanford.smi.protegex.prompt.plugin.SelectionListener;
import edu.stanford.smi.protegex.prompt.plugin.util.SelectableContainer;
import edu.stanford.smi.protegex.prompt.plugin.util.mapping.MapPluginFacade;
import edu.stanford.smi.protegex.prompt.ui.ActionListPane;
import edu.stanford.smi.protegex.prompt.ui.ActionRenderer;
import edu.stanford.smi.protegex.prompt.ui.ListSplitPane;
import edu.stanford.smi.protegex.prompt.ui.SuggestionListPane;
import edu.stanford.smi.protegex.prompt.ui.TabComponent;
import edu.stanford.smi.protegex.prompt.ui.diffUI.DiffTableView;

public class MarkAsTemporaryAction extends AbstractAction implements SelectionListener {
	private static final long serialVersionUID = 7072947406584077086L;

	private TemporaryMappingManager temporaryMappingManager;

	public MarkAsTemporaryAction(TemporaryMappingManager temporaryMappingManager) {
		super("Mark as temporary mapping", IconConstants.ICON_MARK_AS_TEMPORARY);

		this.temporaryMappingManager = temporaryMappingManager;
		init();

		// listener for handling conflicts between operations being created and
		// operations stored as temporary
		PromptListenerManager.addListener(new PromptListener() {
			public void UIBuilt(TabComponent promptTab, PromptEvent event) {}
			public void diffDone(PromptEvent event) {}
			public void diffTableViewBuilt(DiffTableView view, PromptEvent event) {}
			public void diffUIBuilt(JTabbedPane mainPane, PromptEvent event) {}
			public void initializationDone(PromptEvent event) {}
			public void taskComplete(PromptEvent event, boolean interrupted) {}

			public void operationStarted(Operation operation, PromptEvent event) {
				operationPerformed(operation);
			}

			public void operationCompleted(Operation operation, PromptEvent event) {
				DataLoaderFacade.getInstance().refreshMapping();
			}
		});

		SelectableContainer container = MapPluginFacade.getSelectableContainer(MapPluginFacade.UI_UTILITY_SUGGESTION);
		container.addSelectionListener(this);
	}

	/**
	 * Called when this button is pressed.
	 */
	public void actionPerformed(ActionEvent e) {
		Operation operation = getSelectedOperation();
		temporaryMappingManager.addTemporaryMapping(operation);

		this.setEnabled(false);

		ListSplitPane splitPane = TabComponent.getTodoPane();
		ActionListPane listPane = ((SuggestionListPane) splitPane).getTodoList();
		listPane.repaint();
	}

	/**
	 * Called when a mapping suggestion in Prompt's suggestion list is selected.
	 */
	public void selectionPerformed(Object selectedItem) {
		if (selectedItem instanceof Operation) {
			setButtonState((Operation) selectedItem);
		}
	}

	@SuppressWarnings("unchecked")
	private Operation getSelectedOperation() {
		ListSplitPane splitPane = TabComponent.getTodoPane();
		ActionListPane listPane = ((SuggestionListPane) splitPane).getTodoList();
		int selectedIndex = listPane.getSelectedIndex();

		ArrayList suggestions = (ArrayList) ((SuggestionListPane) splitPane).getTodoList().getActionList();
		return (Operation) suggestions.get(selectedIndex);
	}

	private void setButtonState(Operation operation) {
		if (temporaryMappingManager.isTemporaryOperation(operation)) {
			this.setEnabled(false);
		} else {
			this.setEnabled(true);
		}
	}

	private void init() {
		// update the visualization if the list of temporary mappings change
		temporaryMappingManager.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				DataLoaderFacade.getInstance().refreshMapping();
				setButtonState(getSelectedOperation());
			}
		});
		JTable suggestionTable = getSuggestionTable();
		if (suggestionTable != null) {
			TableColumn column = suggestionTable.getColumnModel().getColumn(0);
			column.setCellRenderer(new ActionNameRenderer());

			column = suggestionTable.getColumnModel().getColumn(1);
			column.setCellRenderer(new ActionArgsRenderer(0));

			column = suggestionTable.getColumnModel().getColumn(2);
			column.setCellRenderer(new ActionArgsRenderer(1));
		}
	}

	private JTable getSuggestionTable() {
		ListSplitPane splitPane = TabComponent.getTodoPane();
		ActionListPane listPane = ((SuggestionListPane) splitPane).getTodoList();

		return listPane.getSuggestionTable();
	}

	/**
	 * When an operation is performed, this method checks for conflicting temporary operations.
	 * 
	 * @param operation
	 *            The operation being performed by Prompt
	 */
	private void operationPerformed(Operation operation) {
		// we only care about merge/mapping operations
		if (operation instanceof MergeClsesOperation) {
			if (temporaryMappingManager.isTemporaryOperation(operation)) {
				temporaryMappingManager.removeTemporaryMapping(operation);
			}
			if (hasConflictingTempOperation(operation)) {
				int result = JOptionPane.showConfirmDialog(null, "There exists conflicting temporary operations for this mapping.  Remove temporary mappings?", "Conflicts", JOptionPane.YES_NO_OPTION);
				if (result == JOptionPane.YES_OPTION) {
					removeConflictingTemporaries(operation);
				}
			}
		}
	}

	/**
	 * Checks to see if the passed in operation conflicts with an existing temporary operation.
	 * 
	 * @param operation
	 * @return True if there is a conflict.
	 */
	private boolean hasConflictingTempOperation(Operation operation) {
		ArrayList<Operation> tempOperations = temporaryMappingManager.getTemporaryMappings();
		for (Operation tempOperation : tempOperations) {
			if (tempOperation.getArgs().getArg(0).equals(operation.getArgs().getArg(0)) || tempOperation.getArgs().getArg(1).equals(operation.getArgs().getArg(1))) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Removes all temporary operations that conflict with the operation being performed.
	 * 
	 * @param operation
	 */
	private void removeConflictingTemporaries(Operation operation) {
		ArrayList<Operation> tempOperations = temporaryMappingManager.getTemporaryMappings();
		for (int i = 0; i < tempOperations.size(); i++) {
			Operation tempOperation = tempOperations.get(i);
			if (tempOperation.getArgs().getArg(0).equals(operation.getArgs().getArg(0)) || tempOperation.getArgs().getArg(1).equals(operation.getArgs().getArg(1))) {
				temporaryMappingManager.removeTemporaryMapping(tempOperation);
				i--;
			}
		}
	}

	// Renderers for column elements
	private class ActionNameRenderer extends ActionRenderer {
		private static final long serialVersionUID = 3055723831204301745L;

		public void load(Object o) {
			if (!(o instanceof Operation)) {
				return;
			}

			Operation operation = (Operation) o;

			setMainString(operation.getShortName());
			if (temporaryMappingManager.isTemporaryOperation(operation)) {
				setMainString("temp");
				Font italicFont = new Font(getFont().getName(), Font.ITALIC, getFont().getSize());
				setTextFont(italicFont);
			} else if (operation.getFromUser()) {
				Font boldFont = new Font(getFont().getName(), Font.BOLD, getFont().getSize());
				setTextFont(boldFont);
			} else {
				Font normalFont = new Font(getFont().getName(), Font.PLAIN, getFont().getSize());
				setTextFont(normalFont);
			}
		}
	}

	private class ActionArgsRenderer extends ActionRenderer {
		private static final long serialVersionUID = 6157481906690548546L;
		
		int _index;

		ActionArgsRenderer(int i) {
			super();
			_index = i;
		}

		public void load(Object o) {
			if (!(o instanceof Operation)) {
				return;
			}

			Operation operation = (Operation) o;
			ActionArgs args = operation.getShortArgs();

			if (temporaryMappingManager.isTemporaryOperation(operation)) {
				Font italicFont = new Font(getFont().getName(), Font.ITALIC, getFont().getSize());
				setTextFont(italicFont);
			} else {
				Font normalFont = new Font(getFont().getName(), Font.PLAIN, getFont().getSize());
				setTextFont(normalFont);
			}

			if (args != null && args.size() > _index) {
				setArgs(new Object[] { args.getArg(_index) });
			} else {
				setArgs(null);
			}
		}
	}
}
